﻿
//_________________________________Copyright (c) 2021,LangGe Co.,Ltd_____________________________
//                                       All rights reserved.
//
//   文件名称：win32file.cpp
//   文件标识：见配置管理计划书
//   描    述：win32文件操作
//
//   当前版本：1.0
//   作    者：张小刚
//   完成日期：2022.02.08
//_______________________________________________________________________________________________

#include "osapi.h"

#if defined WIN32_PC || defined WIN32_PDA

#include <Windows.h>
#include <tchar.h>
#include <direct.h>
#include "stdio.h"

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-8）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char *cPathName)
{
	if (nullptr == cPathName)
	{
		return -1;
	}

	char16_t u16PathName[256] = {0};
	if (osConvertToUTF16(cPathName, u16PathName, 256) <= 0)
	{
		return -1;
	}

	return TRUE == CreateDirectoryW((LPCWSTR)u16PathName, NULL) ? 0 : -1;
}

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-16）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char16_t *cPathName)
{
	if (nullptr == cPathName)
	{
		return -1;
	}

	return TRUE == CreateDirectoryW((LPCWSTR)cPathName, NULL) ? 0 : -1;
}

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-32）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char32_t *cPathName)
{
	if (nullptr == cPathName)
	{
		return -1;
	}

	char16_t u16PathName[256] = {0};
	if (osConvertToUTF16(cPathName, u16PathName, 256) <= 0)
	{
		return -1;
	}

	return TRUE == CreateDirectoryW((LPCWSTR)u16PathName, NULL) ? 0 : -1;
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码：UTF-8）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char *fileName, const uint32_t size)
{
	if (nullptr == fileName || 0 == size)
	{
		return 0;
	}
	char16_t u16FileName[256] = {0};
	const uint32_t ret = GetModuleFileNameW(NULL, (LPWSTR)u16FileName, 256);
	if (0 == ret)
	{
		return 0;
	}
	return osConvertToUTF8(u16FileName, fileName, (int32_t)size);
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码: UTF-16）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char16_t *fileName, const uint32_t size)
{
	if (nullptr == fileName || 0 == size)
	{
		return 0;
	}
	return GetModuleFileNameW(NULL, (LPWSTR)fileName, size);
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码：UTF-32）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char32_t *fileName, const uint32_t size)
{
	if (nullptr == fileName || 0 == size)
	{
		return 0;
	}
	char16_t u16FileName[256] = {0};
	const uint32_t ret = GetModuleFileNameW(NULL, (LPWSTR)u16FileName, 256);
	if (0 == ret)
	{
		return 0;
	}
	return osConvertToUTF32(u16FileName, fileName, (int32_t)size);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-8）
 * @param cLastPath   上一层目录（编码：UTF-8）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char *cPath, char *cLastPath, const uint32_t size)
{
	if (nullptr == cPath || nullptr == cLastPath || 0 == size)
	{
		return 0;
	}
	memset(cLastPath, 0, size * sizeof(char));

	int32_t lPostion = -1;
	const int32_t len = osstrlen(cPath);
	for (int32_t i = 0; i < len; i++)
	{
		if ('\\' == cPath[i] || '/' == cPath[i])
		{
			lPostion = i;
		}
	}

	if (lPostion < 0 || static_cast<uint32_t>(lPostion) >= size)
	{
		return 0;
	}

	for (int32_t i = 0; i < lPostion; i++)
	{
		cLastPath[i] = cPath[i];
	}

	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-16）
 * @param cLastPath   上一层目录（编码：UTF-16）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char16_t *cPath, char16_t *cLastPath, const uint32_t size)
{
	if (nullptr == cPath || nullptr == cLastPath || 0 == size)
	{
		return 0;
	}
	memset(cLastPath, 0, size * sizeof(char16_t));

	int32_t lPostion = -1;
	const int32_t len = osstrlen(cPath);
	for (int32_t i = 0; i < len; i++)
	{
		if (u'\\' == cPath[i] || u'/' == cPath[i])
		{
			lPostion = i;
		}
	}

	if (lPostion < 0 || static_cast<uint32_t>(lPostion) >= size)
	{
		return 0;
	}

	for (int32_t i = 0; i < lPostion; i++)
	{
		cLastPath[i] = cPath[i];
	}

	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-32）
 * @param cLastPath   上一层目录（编码：UTF-32）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char32_t *cPath, char32_t *cLastPath, const uint32_t size)
{
	if (nullptr == cPath || nullptr == cLastPath || 0 == size)
	{
		return 0;
	}
	memset(cLastPath, 0, size * sizeof(char32_t));

	int32_t lPostion = -1;
	const int32_t len = osstrlen(cPath);
	for (int32_t i = 0; i < len; i++)
	{
		if (U'\\' == cPath[i] || U'/' == cPath[i])
		{
			lPostion = i;
		}
	}

	if (lPostion < 0 || static_cast<uint32_t>(lPostion) >= size)
	{
		return 0;
	}

	for (int32_t i = 0; i < lPostion; i++)
	{
		cLastPath[i] = cPath[i];
	}

	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-8）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char fileName[256] = {0};
	if (0 == osGetModuleFileName(fileName, 256))
	{
		return 0;
	}

	return osGetLastDirectory(fileName, cPath, size);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-16）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char16_t *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char16_t fileName[256] = {0};
	if (0 == osGetModuleFileName(fileName, 256))
	{
		return 0;
	}

	return osGetLastDirectory(fileName, cPath, size);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-32）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char32_t *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char32_t fileName[256] = {0};
	if (0 == osGetModuleFileName(fileName, 256))
	{
		return 0;
	}

	return osGetLastDirectory(fileName, cPath, size);
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-8）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char path[256] = {0x00};
	if (0 == osGetExePath(path, 256))
	{
		return 0;
	}

	return osGetLastDirectory(path, cPath, size);
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-16）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char16_t *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char16_t path[256] = {0};
	if (0 == osGetExePath(path, 256))
	{
		return 0;
	}

	return osGetLastDirectory(path, cPath, size);
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-32）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char32_t *cPath, const uint32_t size)
{
	if (nullptr == cPath || 0 == size)
	{
		return 0;
	}

	char32_t path[256] = {0};
	if (0 == osGetExePath(path, 256))
	{
		return 0;
	}

	return osGetLastDirectory(path, cPath, size);
}

/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-8）
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note 当文件处于安卓系统下的 assets 目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char *cFileName, const bool bReadOnly, const bool bCreateNew)
{
	if (nullptr == cFileName)
	{
		return nullptr;
	}

	char16_t u16FileName[256] = {0x00};
	if (osConvertToUTF16(cFileName, u16FileName, 256) <= 0)
	{
		return nullptr;
	}

	return osOpenFile(u16FileName, bReadOnly, bCreateNew);
}
/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-16）
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char16_t *cFileName, const bool bReadOnly, const bool bCreateNew)
{
	if (nullptr == cFileName)
	{
		return nullptr;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)malloc(sizeof(OsFileHandle));
	if (nullptr == pFileHandle)
	{
		return nullptr;
	}
	memset(pFileHandle, 0, sizeof(OsFileHandle));

	int32_t RW = 0;
	if (bReadOnly)
	{
		RW = GENERIC_READ;
	}
	else
	{
		RW = GENERIC_READ | GENERIC_WRITE;
	}

	int32_t OC = 0;
	if (bCreateNew)
	{
		OC = CREATE_ALWAYS;
	}
	else
	{
		OC = OPEN_EXISTING;
	}

	HANDLE ret = CreateFileW((LPCWSTR)cFileName, RW, 0, NULL, OC, 0, NULL);
	if (INVALID_HANDLE_VALUE == ret)
	{
		free(pFileHandle);

		return nullptr;
	}

	pFileHandle->m_pFileHandle = ret;
	pFileHandle->m_bAssets = false;

	return (void *)pFileHandle;
}

/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-32）
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char32_t *cFileName, const bool bReadOnly, const bool bCreateNew)
{
	if (nullptr == cFileName)
	{
		return nullptr;
	}

	char16_t u16FileName[256] = {0x00};
	if (osConvertToUTF16(cFileName, u16FileName, 256) <= 0)
	{
		return nullptr;
	}

	return osOpenFile(u16FileName, bReadOnly, bCreateNew);
}

/**
 * @brief 关闭指定文件
 * @param hCom      文件句柄
 * @param bAssets   标记是否为安卓assets目录下文件句柄
 */
void osCloseFile(void **hCom)
{
	if (nullptr == hCom)
	{
		return;
	}
	if (nullptr == *hCom)
	{
		return;
	}
	OsFileHandle *pFileHandle = (OsFileHandle *)(*hCom);
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return;
	}

	CloseHandle(pFileHandle->m_pFileHandle);
	pFileHandle = nullptr;

	free(*hCom);
	*hCom = nullptr;
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-8）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char *cPath)
{
	if (nullptr == cPath)
	{
		return false;
	}

	char16_t u16Path[256] = {0x0000};
	if (osConvertToUTF16(cPath, u16Path, 256) <= 0)
	{
		return false;
	}

	return osIsPathExist(u16Path);
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-16）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char16_t *cPath)
{
	if (nullptr == cPath)
	{
		return false;
	}

	bool bValue = false;
	WIN32_FIND_DATAW wfd;
	HANDLE hFind = FindFirstFileW((LPCWSTR)cPath, &wfd);
	if ((INVALID_HANDLE_VALUE != hFind) &&
		(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
	{
		bValue = true;
	}

	if (INVALID_HANDLE_VALUE != hFind)
	{
		FindClose(hFind);
	}

	return bValue;
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-32）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char32_t *cPath)
{
	if (nullptr == cPath)
	{
		return false;
	}

	char16_t u16Path[256] = {0x0000};
	if (osConvertToUTF16(cPath, u16Path, 256) <= 0)
	{
		return false;
	}

	return osIsPathExist(u16Path);
}

/**
 * @brief 读取文件
 * @param hFile                      文件句柄
 * @param lpBuffer                   数据缓冲区
 * @param nNumberOfBytesToRead       数据缓冲区字节数
 * @param lpNumberOfBytesRead        实际读取的字节数
 * @return true                      文件读取成功
 * @return false                     文件读取失败
 */
bool osReadFile(void *hFile, void *lpBuffer, const uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead)
{
	if (nullptr == hFile || nullptr == lpBuffer || 0 == nNumberOfBytesToRead)
	{
		return false;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)hFile;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return false;
	}

	const BOOL bResult = ReadFile(pFileHandle->m_pFileHandle, lpBuffer, nNumberOfBytesToRead, (LPDWORD)lpNumberOfBytesRead, 0);
	if (bResult && (*lpNumberOfBytesRead) > 0)
	{
		return true;
	}

	return false;
}

/**
 * @brief 写文件
 * @param hFile                     文件句柄
 * @param lpBuffer                  数据缓冲区
 * @param nNumberOfBytesToWrite     数据字节数
 * @param lpNumberOfBytesWritten    实际写入字节数
 * @return true                     写入成功
 * @return false                    写入失败
 */
bool osWriteFile(void *hFile, void *lpBuffer, const uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten)
{
	if (nullptr == hFile || nullptr == lpBuffer || 0 == nNumberOfBytesToWrite)
	{
		return false;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)hFile;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return false;
	}

	BOOL bResult = WriteFile(pFileHandle->m_pFileHandle, lpBuffer, (DWORD)nNumberOfBytesToWrite, (LPDWORD)lpNumberOfBytesWritten, 0);
	if (bResult)
	{
		return true;
	}

	return false;
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-8）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char *filename, const char *mode)
{
	if (nullptr == filename || nullptr == mode)
	{
		return nullptr;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)malloc(sizeof(OsFileHandle));
	if (nullptr == pFileHandle)
	{
		return nullptr;
	}

	// // we need to open the file as commit mode because
	// // otherwise the fflush will not work correctly
	// char newmode[8];
	// if (osstrlen(mode) > 6)
	// 	return NULL;
	// osstrcpy(newmode, mode);
	// osstrcat(newmode, "c");

	FILE *fp = nullptr;
	const errno_t err = fopen_s(&fp, filename, mode);
	if (0 != err || nullptr == fp)
	{
		free(pFileHandle);
		return nullptr;
	}

	pFileHandle->m_pFileHandle = (void *)fp;
	pFileHandle->m_bAssets = false;

	return (void *)pFileHandle;
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-16）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note   当文件处于安卓系统下的 assets 目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char16_t *filename, const char16_t *mode)
{
	if (nullptr == filename || nullptr == mode)
	{
		return nullptr;
	}

	char u8FileName[256] = {0x00};
	if (osConvertToUTF8(filename, u8FileName, 256) <= 0)
	{
		return nullptr;
	}
	char u8Mode[20] = {0x00};
	if (osConvertToUTF8(mode, u8Mode, 20) <= 0)
	{
		return nullptr;
	}

	return osFopen(u8FileName, u8Mode);
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-32）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   当文件处于 assets 目录中时，cFileName 应该以 assets: 前缀开始
 *         例如： asset:/log/log.log
 * @note 当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char32_t *filename, const char32_t *mode)
{
	if (nullptr == filename || nullptr == mode)
	{
		return nullptr;
	}

	char u8FileName[256] = {0x00};
	if (osConvertToUTF8(filename, u8FileName, 256) <= 0)
	{
		return nullptr;
	}
	char u8Mode[20] = {0x00};
	if (osConvertToUTF8(mode, u8Mode, 20) <= 0)
	{
		return nullptr;
	}

	return osFopen(u8FileName, u8Mode);
}

/**
 * @brief 读取指定文件
 * @param buf            存储读取数据的空间
 * @param size           每个元素大小，以字节为单位
 * @param count          元素个数
 * @param filehandle     文件句柄
 * @return >0            实际读取的元素个数
 * @return <=0           读取失败
 */
int32_t osFread(char *buf, const int32_t size, const int32_t count, void *filehandle)
{
	if (nullptr == buf || size <= 0 || count <= 0 || nullptr == filehandle)
	{
		return OSE_INVALID_PARAM;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return OSE_INVALID_PARAM;
	}

	int32_t readbytes = (int32_t)fread_s((void *)buf, size * count, size, count, (FILE *)pFileHandle->m_pFileHandle);
	if (readbytes == count)
	{
		return readbytes;
	}

	if (ferror((FILE *)pFileHandle->m_pFileHandle))
	{
		return OSE_FAIL;
	}
	else
	{
		return readbytes;
	}
}

/**
 * @brief 将缓冲区中内容，写入文件中
 * @param buf              缓冲区
 * @param size             每个缓冲区元素尺寸
 * @param count            缓冲区中存储元素个数
 * @param filehandle       文件句柄
 * @return >0              实际写入文件元素个数
 * @return <=0             写入失败
 * @note 如果文件位于安卓assets目录下，则不支持此操作，assets目录只读
 */
int32_t osFwrite(const char *buf, const int32_t size, const int32_t count, void *filehandle)
{
	if (nullptr == buf || size <= 0 || count <= 0 || nullptr == filehandle)
	{
		return OSE_INVALID_PARAM;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return OSE_INVALID_PARAM;
	}

	const int32_t writebytes = (int32_t)fwrite((void *)buf, size, count, (FILE *)pFileHandle->m_pFileHandle);
	if (writebytes == count)
	{
		return writebytes;
	}

	if (ferror((FILE *)pFileHandle->m_pFileHandle))
	{
		return OSE_FAIL;
	}
	else
	{
		return writebytes;
	}
}

/**
 * @brief 冲洗流中的信息，强迫将缓冲区内的数据
 *        写回参数filehandle指定的文件中
 * @param filehandle     文件句柄
 * @return  0    操作成功
 * @return !0    操作失败
 * @note 如果文件位于安卓assets目录下，则不支持此操作，assets目录只读
 */
int32_t osFflush(void *filehandle)
{
	if (nullptr == filehandle)
	{
		return -1;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return -2;
	}

	return fflush((FILE *)pFileHandle->m_pFileHandle);
}

/**
 * @brief 设置流filehandle的文件位置为给定的偏移offset，
 *        参数offset意味着从给定的seekmode位置查找的字
 *        节数。
 * @param filehandle     文件句柄
 * @param offset         这是相对seekmode的偏移量，以字节为单位。
 * @param seekmode       这是表示开始添加偏移 offset 的位置。
 *                       SEEK_SET=0	文件的开头
 *                       SEEK_CUR=1	文件指针的当前位置
 *                       SEEK_END=2	文件的末尾
 * @return 0             成功
 * @return !0            失败
 * @note iOS系统目前只支持SEEK_SET的偏移，seekmode将被忽略
 * @note iOS 13.0 以上版本才支持此操作
 */
int32_t osFseek(void *filehandle, const int64_t offset, const int32_t seekmode)
{
	if (nullptr == filehandle || seekmode < 0 || seekmode >= 3)
	{
		return OSE_INVALID_PARAM;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return -2;
	}

	const int32_t modes[] = {SEEK_SET, SEEK_CUR, SEEK_END};
	const int32_t rt = fseek((FILE *)pFileHandle->m_pFileHandle, (long)offset, modes[seekmode]);

	if (0 == rt)
	{
		return OSE_OK;
	}
	else
	{
		return OSE_FAIL;
	}
}

/**
 * @brief 返回给定流filehandle的当前文件位置。
 * @param filehandle    文件句柄
 * @return -1           错误
 * @return !-1          返回位置标识符的当前位置值。
 * @note 如果文件位于安卓assets目录下，则不支持此操作。
 * @note iOS 13.0 以上版本才支持此操作
 */
int64_t osFtell(void *filehandle)
{
	if (nullptr == filehandle)
	{
		return OSE_FAIL;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return OSE_FAIL;
	}

	return ftell((FILE *)pFileHandle->m_pFileHandle);
}

/**
 * @brief 从指定的流filehandle读取一行，并把它存储在buf所指向的字符串内
 *        当读取 (n-1) 个字符时，或者读取到换行符时，或者到达文件末尾时，
 *        它会停止，具体视情况而定。
 * @param buf              这是指向一个字符数组的指针，该数组存储了要读取的字符串。
 * @param size             这是要读取的最大字符数（包括最后的空字符）。通常是使用
 *                         以buf传递的数组长度。
 * @param filehandle       这是指向 FILE 对象的指针，该 FILE 对象标识了要从中读
 *                         取字符的流。
 * @return nullptr         读取失败
 * @return !nullptr        该函数返回相同的buf参数
 * @note 如果文件位于安卓assets目录下，则不支持此操作。
 * @note iOS暂不支持此操作
 */
char *osFgets(char *buf, const int32_t size, void *filehandle)
{
	if (nullptr == buf || size <= 0 || nullptr == filehandle)
	{
		return nullptr;
	}

	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr == pFileHandle->m_pFileHandle)
	{
		return nullptr;
	}

	char *pBuf = fgets(buf, size, (FILE *)pFileHandle->m_pFileHandle);
	if (nullptr == pBuf)
	{
		return nullptr;
	}

	return pBuf;
}

/**
 * @brief 关闭流 filehandle。刷新所有的缓冲区。
 * @param filehandle       文件句柄
 * @return 0               操作成功
 * @return !0              操作失败
 */
int32_t osFclose(void *filehandle)
{
	if (nullptr == filehandle)
	{
		return OSE_FAIL;
	}

	int32_t iRet = OSE_OK;
	OsFileHandle *pFileHandle = (OsFileHandle *)filehandle;
	if (nullptr != pFileHandle->m_pFileHandle)
	{
		iRet = fclose((FILE *)pFileHandle->m_pFileHandle);
	}

	if (0 == iRet)
	{
		free(filehandle);
	}

	return iRet;
}

#endif

//___________________________________________文件结束____________________________________________